package com.mycat.manager.content.shiro;

import com.mycat.auth.constant.AdminState;
import com.mycat.auth.domain.Admin;
import com.mycat.auth.domain.AuthResource;
import com.mycat.auth.domain.Role;
import com.mycat.auth.service.AdminService;
import com.mycat.auth.service.AuthResourceService;
import org.apache.shiro.SecurityUtils;
import org.apache.shiro.authc.*;
import org.apache.shiro.authc.credential.HashedCredentialsMatcher;
import org.apache.shiro.authz.AuthorizationInfo;
import org.apache.shiro.authz.SimpleAuthorizationInfo;
import org.apache.shiro.realm.AuthorizingRealm;
import org.apache.shiro.session.Session;
import org.apache.shiro.subject.PrincipalCollection;
import org.apache.shiro.util.ByteSource;
import org.springframework.beans.factory.annotation.Autowired;

import javax.annotation.Resource;
import javax.annotation.Resources;
import java.util.*;

/**
 * 自定义shiro Realm,进行登录验证,授权
 *
 * @author Roger
 */
public class CustomerUserRealm extends AuthorizingRealm {

    public static final String SESSION_LOGIN_USER = "SESSION_LOGIN_USER";
    public static final String SESSION_LOGIN_USER_ID = "SESSION_LOGIN_USER_ID";
    public static final String SESSION_LOGIN_USER_ROLE_IDS = "SESSION_LOGIN_USER_ROLE_IDS";

    private AdminService adminService;
    private AuthResourceService authResourceService;

    /**
     * 初始化加密认证机制
     */
    public CustomerUserRealm() {
    }

    /**
     * 身份认证/登录
     */
    @Override
    protected AuthenticationInfo doGetAuthenticationInfo(AuthenticationToken token) throws AuthenticationException {
        final String userName = (String) token.getPrincipal(); // principals：身份，即主体的标识属性，可以是任何东西，如用户名、邮箱等
        Admin admin = adminService.findAdmin(new Admin(userName));
        if (null == admin) {
            throw new UnknownAccountException("用户信息不存在,请联系管理员！");
        }
        if (AdminState.locked.getCode().equalsIgnoreCase(admin.getState())) {
            throw new LockedAccountException(AdminState.locked.getMessage());
        }
        if (AdminState.unActivity.getCode().equalsIgnoreCase(admin.getState())) {
            throw new AccountStateException(AdminState.unActivity.getMessage());
        }
        if (AdminState.out.getCode().equalsIgnoreCase(admin.getState())) {
            throw new AccountStateException(AdminState.out.getMessage());
        }
        return new SimpleAuthenticationInfo(userName, admin.getPswd(), ByteSource.Util.bytes(admin.getSalt()),getName());
    }

    /**
     * 授权，即权限验证，验证某个已认证的用户是否拥有某个权限
     */
    @Override
    protected AuthorizationInfo doGetAuthorizationInfo(PrincipalCollection principals) {
        Set<String> roleStrings = new HashSet<>();
        Set<String> permissionStrings = new HashSet<>();

        permissionStrings.add("test:message");

        // 获取当前用户名的角色
        String userName = (String) principals.getPrimaryPrincipal();
        Admin admin = adminService.findAdminRole(new Admin(userName));
        if (null != admin) {
            Session session = SecurityUtils.getSubject().getSession();
            session.setAttribute(SESSION_LOGIN_USER, admin);
            session.setAttribute(SESSION_LOGIN_USER_ID, admin.getId());

            List<Role> roles = admin.getRoles();
            if (null != roles && roles.size() > 0) {
                List<Integer> roleIds = new ArrayList<>(roles.size());
                for (Role role : roles) {
                    if (null != role.getEnName()) {
                        roleStrings.add(role.getEnName());
                    }
                    roleIds.add(role.getId());
                }

                List<AuthResource> resources = authResourceService.findPermissionByRoleIds(roleIds.toArray(new Integer[]{}));
                if (null != resources && resources.size() > 0) {
                    for (AuthResource resource : resources) {
                        if (null != resource.getPermission() && !"".equals(resource.getPermission().trim())) {
                            permissionStrings.add(resource.getPermission());
                        }
                    }
                }

                session.setAttribute(SESSION_LOGIN_USER_ROLE_IDS, roleIds);
            }
        }

        SimpleAuthorizationInfo authorizationInfo = new SimpleAuthorizationInfo();
        authorizationInfo.setRoles(roleStrings);
        authorizationInfo.setStringPermissions(permissionStrings);
        return authorizationInfo;
    }

    public AdminService getAdminService() {
        return adminService;
    }

    public void setAdminService(AdminService adminService) {
        this.adminService = adminService;
    }

    public AuthResourceService getAuthResourceService() {
        return authResourceService;
    }

    public void setAuthResourceService(AuthResourceService authResourceService) {
        this.authResourceService = authResourceService;
    }
}